package trading_strategy.events.filtered;

import trading_strategy.events.*;
import trading_strategy.instruments.ListedInstrument;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Created by IntelliJ IDEA.
 * User: gderoujoux
 * Date: 6 mai 2010
 * Time: 12:05:58
 * To change this template use File | Settings | File Templates.
 */
public class CandleFilter extends DerivedSignal {
    private Date prevEnd;

    public class CandleEvent extends InstrumentEvent {
        Candle candle;

        CandleEvent(ListedInstrument instrument, Candle candle, long ts) {
            super(instrument, ts);
            this.candle = candle;
        }

        public Candle getCandle() {
            return candle;
        }
    }

    Candle currentCandle;
    int candleDurationInMillis;

    public CandleFilter(ListedInstrument instrument, String name, int durationInSeconds) {
        super(name, "FilteredSignalDispatcher", instrument, instrument.getTradeEventProvider());
        candleDurationInMillis = durationInSeconds * 1000;
        EventManager.getInstance().subscribe(this, instrument.getOrderBookProvider());
    }

    public void onTrade(PublicTradeUpdate event) {
        if (event.getInstrument().getId() == 3) {
            int i = 0;
        }
        if (currentCandle == null) {
            currentCandle = new Candle();
            Calendar cal = GregorianCalendar.getInstance();
            if (prevEnd != null) {
                // Start the new candle at the end of the previous one
                cal.setTime(prevEnd);
            } else {
                cal.setTime(new Date(event.getTs() / 1000));
                cal.set(Calendar.MILLISECOND, 0);
                if (candleDurationInMillis >= 1000) {
                    if (candleDurationInMillis >= 60000) {
                        int cds = candleDurationInMillis / 1000;
                        int secValue = cal.get(Calendar.SECOND);
                        cal.set(Calendar.SECOND, (secValue / cds) * cds);
                    } else {
                        // If candle duration over a minute, align to the start of a minute
                        cal.set(Calendar.SECOND, 0);
                    }
                }
            }
            currentCandle.start = cal.getTime();
            cal.add(Calendar.MILLISECOND, candleDurationInMillis);
            currentCandle.end = cal.getTime();
            currentCandle.open = event.getPrice();
        }

        int newTotalQty = currentCandle.tradedQty + event.getQty();
        currentCandle.vwap = ((currentCandle.vwap * currentCandle.tradedQty) + event.getPrice() * event.getQty()) / newTotalQty;
        currentCandle.tradedQty = newTotalQty;
        currentCandle.high = Math.max(currentCandle.high, event.getPrice());
        currentCandle.low = Math.min(currentCandle.low, event.getPrice());
        currentCandle.close = event.getPrice();
        currentCandle.volume = newTotalQty;
    }

    protected void sendCurrentCandle(AbstractMarketEvent event) {
        if (currentCandle != null && event.getDate().after(currentCandle.end)) {
            // Send the candle
            prevEnd = currentCandle.end;
            addEvent(new CandleEvent(instrument, currentCandle, event.getTs()));
            currentCandle = null;
        }
    }

    @Override
    public void onMarketEvent(AbstractMarketEvent event) {
        sendCurrentCandle(event);
        if (event instanceof PublicTradeUpdate) {
            onTrade((PublicTradeUpdate) event);
        }
    }
}
